package com.yy;

import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 描述
 * 作者 雷哥
 */
public class PayService {
    // 支付宝当面付2.0服务
    private static AlipayTradeService tradeService;

    static {
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");
        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder()
                .build();
    }

    // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
    // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
    static String sellerId = "";
    // 商户操作员编号，添加此参数可以为商户操作员做销售统计
    static String operatorId = "test_operator_id";
    // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
    static String storeId = "test_store_id";
    // 支付超时，定义为120分钟
    static String timeoutExpress = "10m";


    /**
     * 支付
     *
     * @param outTradeNo           (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
     * @param subject              (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
     * @param totalAmount          必填) 订单总金额，单位为元，不能超过1亿元
     * @param undiscountableAmount (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
     * @param body                 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
     * @param notifyUrl            回调地址
     * @return
     */
    public static Map<String, Object> pay(String outTradeNo, String subject, String totalAmount, String undiscountableAmount, String body, String notifyUrl) {
        Map<String, Object> map = new HashMap<>();
        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                .setOperatorId(operatorId).setStoreId(storeId)
                .setTimeoutExpress(timeoutExpress)
                .setNotifyUrl(notifyUrl);//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                System.out.println("支付宝预下单成功");
                AlipayTradePrecreateResponse response = result.getResponse();
//                System.out.println(JSON.toJSONString(response));
                map.put("code", 200);
                map.put("msg", "下单成功");
                map.put("quCode", response.getQrCode());
                break;

            case FAILED:
                map.put("code", 500);
                map.put("msg", "支付宝预下单失败");
                break;

            case UNKNOWN:
                map.put("code", 500);
                map.put("msg", "系统异常，预下单状态未知");
                break;

            default:
                map.put("code", 500);
                map.put("msg", "不支持的交易状态，交易返回异常");
                break;
        }
        return map;
    }


    /**
     * 查询支付状态
     *
     * @param outTradeNo 自己系统的订单号
     */
    public static Map<String, Object> queryPay(String outTradeNo) {
        Map<String, Object> map = new HashMap<>();
        AlipayTradeQueryRequestBuilder tradeQueryRequest = new AlipayTradeQueryRequestBuilder();
        tradeQueryRequest.setOutTradeNo(outTradeNo);
        AlipayF2FQueryResult result = tradeService.queryTradeResult(tradeQueryRequest);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                AlipayTradeQueryResponse response = result.getResponse();
                String tradeStatus = response.getTradeStatus();
                map.put("code", 200);
                map.put("msg", "查询成功");
                map.put("tradeStatus", tradeStatus);
                break;
            case FAILED:
                map.put("code", 500);
                map.put("msg", "查询失败");
                map.put("data", result.getResponse().getSubMsg());
                break;
            case UNKNOWN:
                map.put("code", 500);
                map.put("msg", "系统异常");
                map.put("data", result.getResponse().getSubMsg());
                break;
            default:
                map.put("code", 500);
                map.put("msg", "不支持的交易状态");
                map.put("data", result.getResponse().getSubMsg());
                break;
        }
        return map;
    }


    /**
     * 退款
     *
     * @param outTradeNo   (必填) 外部订单号，需要退款交易的商户外部订单号
     * @param refundAmount (必填) 退款金额，该金额必须小于等于订单的支付金额，单位为元
     * @param refundReason (必填) 退款原因，可以说明用户退款原因，方便为商家后台提供统计
     * @param outRequestNo  (可选，需要支持重复退货时必填) 商户退款请求号，相同支付宝交易号下的不同退款请求号对应同一笔交易的不同退款申请，
     */
    public static  Map<String, Object> refund(String outTradeNo, String refundAmount, String refundReason, String outRequestNo) {
        Map<String, Object> map = new HashMap<>();
        // 创建退款请求builder，设置请求参数
        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder();
        if (!StringUtils.hasText(outTradeNo)) {
            throw new RuntimeException("外部订单号不能为空");
        }
        builder.setOutTradeNo(outTradeNo);

        if (!StringUtils.hasText(refundAmount)) {
            throw new RuntimeException("退款金额不能为空");
        }
        builder.setRefundAmount(refundAmount);

        if (!StringUtils.hasText(refundReason)) {
            throw new RuntimeException("退款原因不能为空");
        }
        builder.setRefundReason(refundReason);

        if (StringUtils.hasText(outRequestNo)) {
            builder.setOutRequestNo(outRequestNo);
        }
        builder.setStoreId(storeId);
        AlipayF2FRefundResult result = tradeService.tradeRefund(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                map.put("code", 200);
                map.put("msg", "退款成功");
                map.put("data", result.getResponse().getSubMsg());
                break;

            case FAILED:
                map.put("code", 500);
                map.put("msg", "退款失败");
                map.put("data", result.getResponse().getSubMsg());
                break;

            case UNKNOWN:
                map.put("code", 500);
                map.put("msg", "系统异常");
                map.put("data", result.getResponse().getSubMsg());
                break;
            default:
                map.put("code", 500);
                map.put("msg", "系统异常");
                map.put("data", result.getResponse().getSubMsg());
                break;
        }
        return map;
    }

}
